package stack

import (
	"strconv"
	"strings"
)

// https://leetcode.cn/problems/basic-calculator leetcode-224
// 首先处理所有的空字符串
// 正常思路是两个栈，一个栈放操作数，一个栈放运算符
// 几种特殊情况建议做提前处理，
// 第一种，符号在字符串的第一位，例如-2+1，此时建议在操作数栈中先压入一个0
// 第二种情况，括号内的第一位为符号，例如(-2+3)，此时同样建议在操作数栈中压入一个0
func calculate(s string) int {
	s = trimSpace(s)

	opStack := make([]int32, 0, len(s)/2)
	numStack := make([]int, 0, len(s)/2)

	if s[0] == '+' || s[0] == '-' {
		numStack = append(numStack, 0)
	}

	for i := 0; i < len(s); i++ {
		v := int32(s[i])
		if v == '+' || v == '-' {
			if len(opStack) > 0 && opStack[len(opStack)-1] != '(' {
				num1, num2 := numStack[len(numStack)-2], numStack[len(numStack)-1]
				numStack = numStack[:len(numStack)-2]

				op := opStack[len(opStack)-1]
				opStack = opStack[:len(opStack)-1]

				numStack = append(numStack, cal(num1, num2, op))
				opStack = append(opStack, v)
			} else {
				opStack = append(opStack, v)
			}
		} else if v == '(' {
			opStack = append(opStack, v)
			if s[i+1] == '+' || s[i+1] == '-' {
				numStack = append(numStack, 0)
			}
		} else if v == ')' {
			for {
				op := opStack[len(opStack)-1]
				opStack = opStack[:len(opStack)-1]
				if op == '(' {
					break
				}
				num1, num2 := numStack[len(numStack)-2], numStack[len(numStack)-1]
				numStack = numStack[:len(numStack)-2]
				numStack = append(numStack, cal(num1, num2, op))
			}

		} else {
			j := i
			for j < len(s) {
				if notNumber(int32(s[j])) {
					break
				}
				j++
			}
			val, _ := strconv.Atoi(s[i:j])
			numStack = append(numStack, val)
			i = j - 1
		}
	}
	if len(numStack) == 1 {
		return numStack[0]
	}
	return cal(numStack[0], numStack[1], opStack[0])
}

func notNumber(v int32) bool {
	return v == '+' || v == '-' || v == '(' || v == ')' || v == ' '
}

func cal(a, b int, op int32) int {
	if op == '+' {
		return a + b
	}
	return a - b
}
func trimSpace(s string) string {
	sb := strings.Builder{}
	for i := 0; i < len(s); i++ {
		val := s[i]
		if val == ' ' {
			continue
		}
		sb.WriteByte(val)
	}
	return sb.String()
}
